<template>
  <div class="app-container custom-tree-container">
    <el-card shadow="hover" class="data-table">
      <div class="custom-tree-node">
        <el-switch
          v-model="draggable"
          class="ml-2"
          active-text="开启拖拽"
          inactive-text="关闭拖拽"
          style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
        />
        <div>
          <el-button v-if="draggable" class="ml-2" type="primary" text plain @click="batchSave">
            批量保存
          </el-button>
          <el-button class="ml-2" type="danger" text plain @click="batchRemove">批量删除</el-button>
        </div>
      </div>
      <el-tree
        ref="treeNodeHtml"
        show-checkbox
        :expand-on-click-node="false"
        :data="treeData"
        :props="defaultProps"
        node-key="catId"
        :default-expanded-keys="expandedKey"
        :draggable="draggable"
        :allow-drop="allowDrop"
        @node-drop="handleDrop"
      >
        <template #default="{ node, data }">
          <div class="custom-tree-node">
            <span>{{ node.label }}</span>
            <div class="flex m-0">
              <el-button v-if="node.level <= 2" type="primary" link @click="append(data)">
                新增
              </el-button>
              <el-button type="warning" link @click="edit(data)">修改</el-button>
              <el-button
                v-if="node.childNodes.length === 0"
                type="danger"
                link
                @click="remove(node, data)"
              >
                删除
              </el-button>
            </div>
          </div>
        </template>
      </el-tree>
    </el-card>

    <el-dialog v-model="dialogVisible" :title="title" width="500" :close-on-click-modal="false">
      <el-form v-model="categoryForm">
        <el-form-item label="分类名称">
          <el-input
            v-model="categoryForm.name"
            placeholder="分类名称"
            maxlength="50"
            show-word-limit
            clearable
          />
        </el-form-item>
        <el-form-item label="图标地址">
          <el-input
            v-model="categoryForm.icon"
            placeholder="图标地址"
            maxlength="255"
            show-word-limit
            clearable
          />
        </el-form-item>
        <el-form-item label="计量单位">
          <el-input
            v-model="categoryForm.productUnit"
            placeholder="计量单位"
            maxlength="50"
            show-word-limit
            clearable
          />
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button plain @click="dialogVisible = false">取消</el-button>
          <el-button type="primary" plain @click="submitCategory">确认</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import categoryApi, { Category } from "@/api/product/category.api";
import { AllowDropType, NodeDropType, RenderContentContext } from "element-plus";
import { DragEvents } from "element-plus/es/components/tree/src/model/useDragNode";
import { useTemplateRef } from "vue";

const defaultProps = {
  children: "children",
  label: "name",
};

const treeNodeHtml = useTemplateRef("treeNodeHtml");
const treeData: Ref<Category[]> = ref([]);
type Node = RenderContentContext["node"];
type Data = RenderContentContext["data"];
const expandedKey = ref<string[]>([]);

onMounted(async () => {
  await getCategoryTreeList();
});

const getCategoryTreeList = async () => {
  await categoryApi.getCategoryTreeList().then((data) => {
    treeData.value = data;
  });
};

const draggable = ref(false);
const dialogVisible = ref(false);
const dialogType = ref("");
const title = ref("");
const categoryForm = ref<Category>({
  catId: null,
  name: "",
  parentCid: 0,
  catLevel: 0,
  showStatus: 0,
  sort: 0,
  icon: "",
  productUnit: "",
  productCount: 0,
});

const pid = ref<number[]>([]);

const batchSave = () => {
  if (updateNodes.value.length === 0) {
    ElMessage.warning("请选择要更新的数据");
    return;
  }
  categoryApi.updateCategoryList(updateNodes.value).then(async () => {
    ElMessage.success("菜单更新成功");
    dialogVisible.value = false;
    await getCategoryTreeList();
    expandedKey.value = [...pid.value.map(String)];
    updateNodes.value = [];
    pid.value = [];
  });
};

const batchRemove = () => {
  const checkedNodes = treeNodeHtml.value?.getCheckedNodes() ?? [];

  if (checkedNodes.length === 0) {
    ElMessage.warning("请选择要删除的数据");
    return;
  }

  ElMessageBox.confirm(`确认批量删除【${checkedNodes.map((node) => node.name)}】的菜单？`, "警告", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  }).then(
    async () => {
      categoryApi.removeMenuByIds(checkedNodes.map((node) => node.catId)).then(async () => {
        ElMessage.success("删除成功");
        await getCategoryTreeList();
        expandedKey.value = [...checkedNodes.map((node) => node.parentCid)];
      });
    },
    () => {
      ElMessage.info("已取消删除");
    }
  );
};

const append = (data: Data) => {
  dialogType.value = "add";
  title.value = "新增";
  dialogVisible.value = true;
  categoryForm.value.parentCid = data.catId;
  categoryForm.value.catLevel = +data.catLevel++;
  categoryForm.value.catId = "";
  categoryForm.value.name = "";
  categoryForm.value.icon = "";
  categoryForm.value.productUnit = "";
};

const edit = (data: Data) => {
  dialogType.value = "edit";
  title.value = "修改";
  dialogVisible.value = true;
  // 发送请求，获取最新的数据回显
  categoryApi.getCategoryById(data.catId).then((result) => {
    categoryForm.value = result;
  });
};

const remove = (node: Node, data: Data) => {
  ElMessageBox.confirm(`确认删除【${data.name}】的数据项？`, "警告", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  }).then(
    async () => {
      categoryApi.removeMenuByIds([data.catId]).then(async () => {
        ElMessage.success("删除成功");
        await getCategoryTreeList();
        expandedKey.value = [node.parent.data.catId];
      });
    },
    () => {
      ElMessage.info("已取消删除");
    }
  );
};

const submitCategory = () => {
  if (!categoryForm.value.name) {
    ElMessage.error("分类名称不能为空");
    return;
  }

  if (dialogType.value === "add") {
    categoryApi.addCategory(categoryForm.value).then(async () => {
      ElMessage.success("添加成功");
      dialogVisible.value = false;
      await getCategoryTreeList();
      expandedKey.value = [`${categoryForm.value.parentCid}`];
    });
  } else if (dialogType.value === "edit") {
    const { catId, name, icon, productUnit } = categoryForm.value;
    categoryApi.updateCategory({ catId, name, icon, productUnit }).then(async () => {
      ElMessage.success("更新成功");
      dialogVisible.value = false;
      await getCategoryTreeList();
      expandedKey.value = [`${categoryForm.value.parentCid}`];
    });
  }
};

const allowDrop = (draggingNode: Node, dropNode: Node, type: AllowDropType) => {
  // 1、被拖动的当前节点以及所在的父节点总层数不能大于3
  let countLevel: number;

  // 1）被拖动的当前总层数
  const currentLevelCount = countCurrentLevel(draggingNode);

  // 2）拖动目标位置的层数
  if (type === "inner") {
    countLevel = dropNode.level + currentLevelCount;
  } else {
    countLevel = dropNode.parent.level + currentLevelCount;
  }

  return countLevel <= 3;
};

const countCurrentLevel = (draggingNode: Node): number => {
  if (draggingNode.childNodes.length === 0) {
    return 1;
  }
  return +countCurrentLevel(draggingNode.childNodes[0]) + 1;
};

const updateNodes = ref<Category[]>([]);

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const handleDrop = (draggingNode: Node, dropNode: Node, dropType: NodeDropType, _: DragEvents) => {
  // 1、当前节点最新的父节点 ID
  let pCid: number;
  // 2、当前拖拽节点的最新顺序
  let siblings: Node[];
  if (dropType === "inner") {
    pCid = dropNode.data.catId;
    siblings = dropNode.childNodes;
  } else {
    pCid = dropNode.parent.data.catId ?? 0;
    siblings = dropNode.parent.childNodes;
  }

  pid.value.push(pCid);
  // 3、当前拖拽节点的最新层级
  for (let i = 0; i < siblings.length; i++) {
    const currentCatId = siblings[i].data.catId;
    const currentCatLevel = siblings[i].level;
    const updateNode: Category = { catId: currentCatId, sort: i };

    if (currentCatId === draggingNode.data.catId) {
      let catLevel = draggingNode.level;

      if (currentCatLevel !== draggingNode.level) {
        // 如果当前拖拽节点的层级发生了变化，需要更新层级
        catLevel = currentCatLevel;
        // 修改子节点层级
        updateChildNodeLevel(siblings[i]);
      }

      // 如果遍历的是当前正在拖拽的节点，还需要改父ID
      updateNode.parentCid = pCid;
      updateNode.catLevel = catLevel;
    }
    updateNodes.value.push(updateNode);
  }
};

const updateChildNodeLevel = (node: Node) => {
  const childNodes = node.childNodes;

  if (childNodes.length === 0) {
    return;
  }

  childNodes.forEach((child: Node) => {
    updateNodes.value.push({ catId: child.data.catId, catLevel: child.level });
    updateChildNodeLevel(child);
  });
};
</script>

<style scoped lang="scss">
.custom-tree-node {
  display: flex;
  flex: 1;
  align-items: center;
  justify-content: space-between;
  padding-right: 8px;
  font-size: 14px;
}
</style>
